#include "exception.hpp"
#include "global_variable.hpp"
#include "handle.hpp"
#include "spdlog/common.h"
#include <pybind11/cast.h>
#include <pybind11/iostream.h>
#include <pybind11/pybind11.h>
#include <pybind11/pytypes.h>

PYBIND11_MODULE(shmpy, m) {
  namespace loglevel = spdlog::level;
  auto loglevelModule = m.def_submodule("log_level");

  py::enum_<spdlog::level::level_enum>(loglevelModule, "LogLevel")
      .value("debug", loglevel::debug)
      .value("info", loglevel::info)
      .value("warn", loglevel::warn)
      .value("trace", loglevel::trace)
      .value("error", loglevel::err)
      .value("off", loglevel::off)
      .export_values();

  // setup
  init_mutex_attr();
  m.def("set_logfile", set_logfile);
  m.def("get_logfile", []() -> std::string_view { return LOGFILE; });
  m.def("set_loglevel", set_loglevel,
        "set log level for new create shmpy.Handle");
  m.def("get_loglevel", []() -> loglevel::level_enum { return LOG_LEVEL; });

  py::class_<Handle>(m, "Handle")
      .def(py::init<std::string_view, std::uint32_t &&>(),
           py::arg("handle_name"), py::arg("capacity"))
      .def(py::init<std::string_view>(), py::arg("handle_name"))
      .def("insert", &Handle::insert, py::arg("name"), py::arg("data"))
      .def("set", &Handle::set, py::arg("name"), py::arg("data"))
      .def("get", &Handle::get, py::arg("name"))
      .def("del", &Handle::del, py::arg("name"))
      .def_property("loglevel", &Handle::get_loglevel, &Handle::set_loglevel)
      .def_property_readonly("ref_count", &Handle::ref_count)
      .def_property_readonly("capacity", &Handle::capacity)
      .def_property_readonly("size", &Handle::size)
      .def_property_readonly("name", &Handle::name);

  py::register_exception<ShmError>(m, "ShmError");
  py::register_exception<HandleError>(m, "HandleError");
  py::register_exception<VariableError>(m, "VarError");
}